package com.yuntsg.nnsfcp.common.aop;


import com.alibaba.fastjson.JSON;
import com.yuntsg.nnsfcp.common.beans.ResultBean;
import com.yuntsg.nnsfcp.common.exceptions.CheckException;
import com.yuntsg.nnsfcp.common.exceptions.Unlogin2Exception;
import com.yuntsg.ruiijn.database.entity.LogException;
import common.util.DateUtils;
import common.util.IPUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * 处理和包装异常
 *
 * @time:2019年01月01日21:10:36
 */
@Slf4j
@Aspect
@Component
public class ControllerAOP {

    @Pointcut("execution(public com.yuntsg.nnsfcp.common.beans.ResultBean *(..))")
    public void controllerMethod() {

    }

    @Around("controllerMethod()")
    public Object handlerControllerMethod(ProceedingJoinPoint pjp) {
        long startTime = System.currentTimeMillis();
        ResultBean<?> result;
        try {
            result = (ResultBean<?>) pjp.proceed();
        } catch (Throwable e) {
            result = handlerException(pjp, e);
            MethodSignature signature = (MethodSignature) pjp.getSignature();
            LogException logException = new LogException();

            // 获取切入点所在的方法
            Method method = signature.getMethod();
            // 获取切入点所在的方法
            logException.setMethod(method.toString());
            // 获取请求的类名
            String className = pjp.getTarget().getClass().getName();
            // 请求方法名
            logException.setClassName(className);
            String methodName = method.getName();
            logException.setClassName(className + "." + methodName);
            // 请求参数
            try {
                Map<String, Object> rtnMap = convertMap(pjp, method);
                String params = JSON.toJSONString(rtnMap);
                // 请求参数
                logException.setParams(params);
            } catch (Exception exception) {

            }

//            //异常的名称
//            logException.setEname(e.getClass().getName());
//            //异常信息
//            logException.setEmessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
//            //异常的URL
//            logException.setEurl(request.getRequestURI());
//            //异常的IP
//            logException.setEip(IPUtil.getIpAddr(request));
//            //出现异常的时间
//            logException.setEtime(DateUtils.strToLong(System.currentTimeMillis()));
//            //异常打印的时间
//            logException.setTime(DateUtils.longToStr(System.currentTimeMillis()));
//            exceptionMapper.insert(logException);
            result = handlerException(pjp, e);
        }


        return result;
    }

    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    private String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer stringBuffer = new StringBuffer();
        for (StackTraceElement stet : elements) {
            stringBuffer.append(stet + "\n");
        }
        return exceptionName + ":" + exceptionMessage + "\n\t" + stringBuffer.toString();
    }

    /**
     * 转换request 请求参数
     *
     * @param joinPoint
     * @param method
     * @return
     */
    private Map<String, Object> convertMap(JoinPoint joinPoint, Method method) {
        // 参数值
        Object[] args = joinPoint.getArgs();
        ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
            if (args == null || args.length == 0) {
                paramMap.put(parameterNames[i], "none");
                continue;
            }
            String argsStr = "";
            if (args[i] != null) {
                argsStr = JSON.toJSONString(args[i]);
            }
            String param = "";
            if (parameterNames[i] != null) {
                param = parameterNames[i];
            }

            paramMap.put(param, argsStr);
        }
        return paramMap;
    }

    private ResultBean<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {
        ResultBean<?> result = new ResultBean();
        // 登陆异常 1
        if (e instanceof Unlogin2Exception) {
            result.setMsg("Unlogin");
            result.setCode(ResultBean.NO_LOGIN);
        }
//        // 没有权限 2
//        else if (e instanceof UnauthorizedException) {
//            result.setMsg("NO PERMISSION: " + e.getMessage());
//            result.setCode(ResultBean.NO_PERMISSION);
//        }

        // 已知异常 3
        else if (e instanceof CheckException) {
            result.setMsg(e.getLocalizedMessage());
            result.setCode(ResultBean.CHECK_FAIL);
        } else if (e instanceof CheckException) {
            result.setCode(ResultBean.CHECKSMS);
            result.setMsg(e.getLocalizedMessage());
        } else {
            log.error(pjp.getSignature() + " error ", e);
            //TODO 未知的异常，应该格外注意，可以发送邮件通知等
            result.setMsg(e.toString());
            result.setCode(ResultBean.UNKNOWN_EXCEPTION);
        }

        return result;
    }
}
